package com.factory;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.util.concurrent.RateLimiter;
import com.utils.SpringBeanUtil;
import com.utils.ThreadPoolUtils;
import com.zbkj.crmeb.enums.task.TaskTypeEnums;
import com.zbkj.crmeb.handler.orderproduct.OrderProductInterface;
import com.zbkj.crmeb.plat.by.dto.Result;
import com.zbkj.crmeb.store.model.StoreProduct;
import com.zbkj.crmeb.store.model.Task;
import com.zbkj.crmeb.store.service.TaskService;
import com.zbkj.crmeb.task.plat.PlatOperateInterface;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;

@Component
@Slf4j
public class TaskProcessEngineFactory {

    private static String envValue;
    @Value("${spring.profiles.active}")
    public void setEnv(String env) {
        envValue = env;
    }

    private static TaskService taskService;
    @Autowired
    public void setTaskService(TaskService service) {
        taskService = service;
    }

    private final static ExecutorService THREAD_POOL = ThreadPoolUtils.getThread();

    // 暂时固定三次
    private final static Integer MAX_RETRY = 3;

    public static boolean batchSubmitTask(List<Task> tasks){
        if (CollectionUtils.isEmpty(tasks)){
            return false;
        }
        List<List<Task>> partition = ListUtils.partition(tasks, 50);
        CompletableFuture[] array = partition.stream().map(k -> CompletableFuture.runAsync(() -> {
            for (Task task : k) {
                submitTask(task);
            }
        },THREAD_POOL)).toArray(CompletableFuture[]::new);
        try {
            CompletableFuture.allOf(array).get(10, TimeUnit.MINUTES);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    public static String submitTask(Task task){
        if (null == task){
            return "";
        }
        boolean b = taskService.saveOrUpdate(task);
        if (b){
            return task.getTaskId();
        }
        return "";
    }

    public static boolean executeTask(){
        if (Objects.equals(envValue,"test")||Objects.equals(envValue,"dev")){
            log.info("当前环境暂不推送商品, env:{}",envValue);
            return true;
        }
        // 不是运行中或者完成的都捞出来
        int count = taskService.count(Wrappers.<Task>lambdaQuery().
                notIn(Task::getTaskType, TaskTypeEnums.RUNNING.getCode(), TaskTypeEnums.TERMINATE.getCode()).lt(Task::getMaxRetry,MAX_RETRY));
        if (count == 0){
            log.info("未查询到需要执行的任务");
            return true;
        }
        int pageSize = 10;
        int maxPage = (count + 9) / pageSize;
        int currPage = 1;
        while (currPage<=maxPage){
            Page<Task> page = PageHelper.startPage(currPage, pageSize);

            try {
                List<Task> taskList = page.getResult();
                // 查询任务
                taskService.list(Wrappers.<Task>lambdaQuery().
                        notIn(Task::getTaskType, TaskTypeEnums.RUNNING.getCode(), TaskTypeEnums.TERMINATE.getCode()).lt(Task::getMaxRetry,MAX_RETRY).orderByDesc(Task::getId));
                if (CollectionUtils.isEmpty(taskList)){
                    continue;
                }
                for (Task task : taskList) {
                    try {
                        log.info("开始执行任务，参数:{}",JSON.toJSONString(task));
                        boolean result = doExecuteTask(task);
                        log.info("结束执行任务，返回:{}",JSON.toJSONString(task));
                        task.setGmtModified(new Date());
                        taskService.updateById(task);
                    }catch (Exception e){
                        log.error("执行任务失败,任务Id:{}, 任务名:{},",task.getTaskId(),task.getTaskName(),e);
                    }
                }
            }finally {
                currPage++;
            }
        }
        return true;
    }

    private static boolean doExecuteTask(Task task) {
        if (null == task){
            return false;
        }
        try {
            String params = task.getFeature("params");
            TaskParamsDto taskParamsDto = JSON.parseObject(params, TaskParamsDto.class);
            if (null == taskParamsDto || StringUtils.isBlank(taskParamsDto.getTaskHandler())){
                task.setTaskType(TaskTypeEnums.TERMINATE.getCode());
                task.addFeature("result","task handle is null");
                throw new RuntimeException("task handle is null");
            }
            PlatOperateInterface bean = null;
            try {
                bean = SpringBeanUtil.getBean(taskParamsDto.getTaskHandler(), PlatOperateInterface.class);
            }catch (Exception e){
                task.setTaskType(TaskTypeEnums.TERMINATE.getCode());
                task.addFeature("result","task handle is not found");
                throw new RuntimeException("task handle is not fund");
            }
            Result execute = null;
            try {
                execute = bean.execute(taskParamsDto);
            }catch (Exception e){
                task.setTaskType(TaskTypeEnums.EXCEPTION.getCode());
                task.addFeature("result",e.getMessage().substring(0,Math.min(e.getMessage().length(), 300)));
                throw new RuntimeException("task handle exception");
            }
            if (null != execute && execute.isSuccess()){
                task.setTaskType(TaskTypeEnums.TERMINATE.getCode());
                task.addFeature("result","task handle success");
                return true;
            }
            task.setTaskType(TaskTypeEnums.EXCEPTION.getCode());
            task.addFeature("result",null != execute?execute.getMessage().substring(0,Math.min(execute.getMessage().length(), 300)):"task handle exception");
        }catch (Exception e){
            log.error("任务执行失败:",e);
        }finally {
            task.setMaxRetry(task.getMaxRetry()+1);
        }
        return false;
    }




}
